#ifndef _PROTOCOL_HPP_20120414
#define _PROTOCOL_HPP_20120414

#include "base.hpp"
#include "streamer.hpp"

using namespace mina;

namespace protocol
{
	class Protocol 
	{
		public :
			const static uint32_t MAGIC         = 0x12133121;
			const static uint32_t LENGTH        = sizeof(uint32_t) * 2 + sizeof(uint16_t) * 2;

			const static uint32_t  LENGTH_POS   = 0; 
			const static uint32_t  MAGIC_POS    = sizeof(uint32_t);
			const static uint32_t  CMD0_POS     = MAGIC_POS  + sizeof(uint32_t);
			const static uint32_t  CMD1_POS     = CMD0_POS   + sizeof(uint16_t);
			const static uint32_t  SEQ_POS      = CMD1_POS   + sizeof(uint16_t);

		public :
			Protocol(uint16_t cmd0, uint16_t cmd1)
				: _length(0),
				  _magic(MAGIC),
				  _cmd0(cmd0),
				  _cmd1(cmd1)
			{
			}

			virtual ~Protocol() {}

			uint32_t protocol_type() const { return (((uint32_t)_cmd0) << 16) | ((uint32_t)_cmd1); }
			uint16_t cmd0() const { return _cmd0; }
			uint16_t cmd1() const { return _cmd1; }

			void serialize(Streamer & streamer)
				{
					streamer & _length
							 & _magic
							 & _cmd0
							 & _cmd1
					         & _seq_num;
				}

			virtual const std::string to_string() const
			{
				std::ostringstream oss;

				oss << "head: {length: " << _length
					<< ", magic: " << _magic
					<< ", cmd0: " << _cmd0
					<< ", cmd1: " << _cmd1
					<< ", seq_num: " << _seq_num
					<< "}";

				return oss.str();
			}

			uint32_t set_length()
			{
				_length  = size();
				return _length;
			}

			virtual uint32_t size() const
			{
				return (uint32_t)(sizeof(uint32_t) * 3 + sizeof(uint16_t) * 2);
			}

		public :
			uint32_t    _length;
			uint32_t    _magic;

			uint16_t    _cmd0;
			uint16_t    _cmd1;
			uint32_t    _seq_num;
	};
};

#endif

